import '@testing-library/jest-dom';
import { beforeAll, afterAll, afterEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import { server } from './mocks/server';

// 启动 MSW 服务器
beforeAll(() => {
  server.listen({ onUnhandledRequest: 'error' });
});

// 每个测试后清理
afterEach(() => {
  cleanup();
  server.resetHandlers();
});

// 关闭 MSW 服务器
afterAll(() => {
  server.close();
});

// 模拟 Tauri API
const mockTauri = {
  invoke: vi.fn(),
  listen: vi.fn(),
  emit: vi.fn(),
  convertFileSrc: vi.fn((src: string) => src),
};

// 全局模拟
Object.defineProperty(window, '__TAURI__', {
  value: mockTauri,
  writable: true,
});

// 模拟 matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: vi.fn(),
    removeListener: vi.fn(),
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
});

// 模拟 ResizeObserver
global.ResizeObserver = vi.fn().mockImplementation(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

// 模拟 IntersectionObserver
global.IntersectionObserver = vi.fn().mockImplementation(() => ({
  observe: vi.fn(),
  unobserve: vi.fn(),
  disconnect: vi.fn(),
}));

// 模拟 localStorage
const localStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
};
Object.defineProperty(window, 'localStorage', {
  value: localStorageMock,
});

// 模拟 sessionStorage
const sessionStorageMock = {
  getItem: vi.fn(),
  setItem: vi.fn(),
  removeItem: vi.fn(),
  clear: vi.fn(),
};
Object.defineProperty(window, 'sessionStorage', {
  value: sessionStorageMock,
});

// 模拟 navigator
Object.defineProperty(navigator, 'clipboard', {
  value: {
    writeText: vi.fn(),
    readText: vi.fn(),
  },
  writable: true,
});

// 模拟 URL.createObjectURL
global.URL.createObjectURL = vi.fn();
global.URL.revokeObjectURL = vi.fn();

// 扩展 expect 匹配器
expect.extend({
  toBeInTheDocument: (received) => {
    const pass = received && document.body.contains(received);
    return {
      message: () => `expected element ${pass ? 'not ' : ''}to be in the document`,
      pass,
    };
  },
});

// 测试工具函数
export const createMockTauriInvoke = (responses: Record<string, any>) => {
  return vi.fn().mockImplementation((command: string, args?: any) => {
    if (responses[command]) {
      if (typeof responses[command] === 'function') {
        return Promise.resolve(responses[command](args));
      }
      return Promise.resolve(responses[command]);
    }
    return Promise.reject(new Error(`Mock not found for command: ${command}`));
  });
};

// 清理函数
export const resetMocks = () => {
  vi.clearAllMocks();
  localStorageMock.getItem.mockClear();
  localStorageMock.setItem.mockClear();
  localStorageMock.removeItem.mockClear();
  localStorageMock.clear.mockClear();
  sessionStorageMock.getItem.mockClear();
  sessionStorageMock.setItem.mockClear();
  sessionStorageMock.removeItem.mockClear();
  sessionStorageMock.clear.mockClear();
};

// 测试数据工厂
export const createTestUser = (overrides = {}) => ({
  id: '1',
  name: 'Test User',
  email: 'test@example.com',
  avatar: 'https://example.com/avatar.jpg',
  ...overrides,
});

export const createTestConfig = (overrides = {}) => ({
  id: 'default',
  theme: 'system',
  language: 'zh-CN',
  auto_start: false,
  minimize_to_tray: true,
  notifications: true,
  shortcuts: JSON.stringify({
    toggleWindow: 'CmdOrCtrl+Shift+H',
    newItem: 'CmdOrCtrl+N',
    search: 'CmdOrCtrl+F',
  }),
  created_at: new Date().toISOString(),
  updated_at: new Date().toISOString(),
  ...overrides,
});

// 异步测试工具
export const waitForNextTick = () => new Promise(resolve => setTimeout(resolve, 0));

export const waitForCondition = async (
  condition: () => boolean,
  timeout = 5000,
  interval = 100
) => {
  const start = Date.now();
  while (!condition() && Date.now() - start < timeout) {
    await new Promise(resolve => setTimeout(resolve, interval));
  }
  if (!condition()) {
    throw new Error('Condition not met within timeout');
  }
};

// 错误边界测试组件
export const TestErrorBoundary = ({ children, onError }: {
  children: React.ReactNode;
  onError?: (error: Error) => void;
}) => {
  const [hasError, setHasError] = React.useState(false);

  React.useEffect(() => {
    const handleError = (error: ErrorEvent) => {
      setHasError(true);
      onError?.(error.error);
    };

    window.addEventListener('error', handleError);
    return () => window.removeEventListener('error', handleError);
  }, [onError]);

  if (hasError) {
    return <div data-testid="error-boundary">Something went wrong</div>;
  }

  return <>{children}</>;
};
